package pl.edu.pw.perg.compinfodb.datamodel;

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.JComboBox;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.search.Searchable;

import pl.edu.pw.perg.compinfodb.entities.ElementType;
import pl.edu.pw.perg.compinfodb.entities.PhysicalElement;
import pl.edu.pw.perg.compinfodb.entities.VirtualElement;
import pl.edu.pw.perg.compinfodb.entities.field.Field;
import pl.edu.pw.perg.compinfodb.ui.ColorRenderer;

public class ElementTableModel implements TableModel, ListSelectionListener,
		IStructureTreeSelectionListener, IElementTypeSelectionListener,
		ISearchFilterListener {

	private ElementDataList datalist;
	private String[] columnNames;
	private final String[] constColumnsNames = TableData.getConstHeaders();
	private List<TableModelListener> listeners = new LinkedList<TableModelListener>();
	private List<IPhysicalElementSelectionListener> peListeners = new ArrayList<IPhysicalElementSelectionListener>();
	private List<SearchTableModel> searchTableModels = new ArrayList<SearchTableModel>();
	private FlexibleTableColumnModel tcm = new FlexibleTableColumnModel(
			new ColorRenderer());

	public ElementTableModel(ElementDataList list) {
		datalist = list;
		columnNames = constColumnsNames;
//		recreateColumnModel();
	}

	@SuppressWarnings("unchecked")
	public Class getColumnClass(int column) {
		return String.class;
	}

	public int getColumnCount() {
		return columnNames.length;
	}

	public String getColumnName(int columnIndex) {
		return columnNames[columnIndex];
	}

	public Object getValueAt(int row, int column) {
		if (datalist.get(row) == null)
			return null;
		return datalist.get(row).getValue(columnNames[column]);
	}

	public void setElementType(ElementType type) {
		datalist.setTypeFilter(type);
		int attrsCount = 0;
		Iterator<Field> it = null;
		List<String> columns = new ArrayList<String>();

		if (type != null) {
			for (it = type.getFields().iterator(); it.hasNext();) {
				String string = (String) it.next().getFieldName();
				columns.add(string);
			}
		}
		columns.addAll(Arrays.asList(constColumnsNames));

		columnNames = columns.toArray(new String[columns.size()]);
		datalist.search();
		recreateColumnModel();
	}

	public void recreateColumnModel() {
		for (TableModelListener l : listeners) {
			JXTable t = ((JXTable) l);
			tcm.setColumnNames(columnNames);
			t.setColumnModel(tcm);
			t.createDefaultColumnsFromModel();
			t.packAll();
			columnModelChanged();
		}
	}

	public void search(Map<String, String> filter) {
		datalist.search(filter);
	}

	public void addTableModelListener(TableModelListener l) {
		listeners.add(l);

	}

	public void addPhysicalElementSelectionListener(
			IPhysicalElementSelectionListener pes) {
		peListeners.add(pes);
	}

	public int getRowCount() {
		return datalist.size();
	}

	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return false;
	}

	public void removeTableModelListener(TableModelListener l) {
		listeners.remove(l);

	}

	public void setValueAt(Object value, int rowIndex, int columnIndex) {

	}

	public void actionPerformed(ActionEvent e) {
		JComboBox cb = (JComboBox) e.getSource();
		setElementType((ElementType) cb.getModel().getSelectedItem());

	}

	public void selectionChanged(VirtualElement ve) {
		setElementType(ve.getElementType());
		reloadTable();
	}

	public void valueChanged(ListSelectionEvent e) {
		int row = ((ListSelectionModel) e.getSource())
				.getAnchorSelectionIndex();
		TableData td = datalist.get(row);
		if (td == null)
			return;
		PhysicalElement ce = td.getPe();
		for (IPhysicalElementSelectionListener pe : peListeners) {

			pe.selectionChanged(ce);
		}

	}
	
	public void reloadTable(){
		for (TableModelListener table : listeners) {
			table.tableChanged(new TableModelEvent(this));
		}
	}

	public void selectionChanged(ElementType selectedElement) {
		setElementType(selectedElement);
		for (IPhysicalElementSelectionListener pe : peListeners) {
			pe.selectionChanged(null);
		}
		reloadTable();
	}

	// public void switchToSearchMode(boolean searchMode) {
	// System.out.println("called");
	//		
	// }

	public void addColumnModelListener(SearchTableModel stm) {
		searchTableModels.add(stm);
	}

	public void columnModelChanged() {
		for (SearchTableModel stm : searchTableModels) {
			stm.setColumnModel(tcm);
		}
	}

//	public void setSearchFilter(Map<String, String> filter) {
//
//	}

	public void filterChanged(Map<String, String> filter) {
		search(filter);
		reloadTable();
	}
}
